<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>箭头函数使用注意点</title>
</head>
<body>
<script type='text/javascript'>
    // 1. 函数体的this对象，在箭头函数里是固定的；是定义时所在的对象，非使用时所用对象
        function foo() {
          setTimeout(() => {
            console.log('id:', this.id);
          }, 100);
        } // foo.call({ id: 42 }); this 总是指向 函数定义 生效时所在的对象 即foo
        /*
        function foo(){
          setTimeout(function(){
            console.log('id:', this.id);
          }, 100)
        }*///foo.call({ id: 42 }); setTimeout 在foo中调用，而foo在全局下，所用输出 21
        var id = 21;
        foo.call({ id: 42 }); // id: 42

        /**** 箭头函数 可以让setTimeout里面的 this 绑定到定义时【定义谁，当然是setTimeout了】所在的作用域 */
        function Timer() {
          this.s1 = 0;
          this.s2 = 0;
          // 箭头函数
          setInterval(() => this.s1++, 1000);
          // 普通函数
          setInterval(function () {
            this.s2++;
          }, 1000);
        }

        var timer = new Timer();
        // 关于这个 this 指向，只能仔细看看这句话了：绑定到定义时【定义谁，当然是setTimeout了】所在的作用域
        setTimeout(() => console.log('s1: ', timer.s1), 3100);// this 是 Timer s1: 3
        setTimeout(() => console.log('s2: ', timer.s2), 3100);// this 是 全局   s2: 0

        /**** 箭头函数还能让 this 指向固定化：有利于封装回调函数 */
        // DOM 事件的回调函数封装在一个对象里面【又是看不懂系列】
        var handler = {
          id: '123456',

          init: function() {
            document.addEventListener('click',
              event => this.doSomething(event.type), false); // this 是 handler【理解 下面句话】
              //箭头函数没有this，导致内层的 this 就是外层代码块的 this：
                // ES6
                function foo() {
                  setTimeout(() => { // this 就是外层的 foo 的 this
                    console.log('id:', this.id);
                  }, 100);
                }
                // ES5
                function foo() {
                  var _this = this;

                  setTimeout(function () {
                    console.log('id:', _this.id);
                  }, 100);
                }

                // 1. 箭头函数 里的 this 练习：
                function foo() {
                  return () => { // 指向外层 this，外层不是箭头函数了 就是foo
                    return () => { // 指向外层 this，可惜外层也是箭头函数
                      return () => { // 指向外层 this，可惜外层也是箭头函数
                        console.log('id:', this.id);
                      };
                    };
                  };
                } // ===> 就一个
                var f = foo.call({id: 1});
                var t1 = f.call({id: 2})()(); // id: 1
                var t2 = f().call({id: 3})(); // id: 1
                var t3 = f()().call({id: 4}); // id: 1 ==> this 一样，输出一样

                // 2. 箭头函数的里没有的变量：arguments、super、new.target
                function foo() {
                  setTimeout(() => {
                    console.log('args:', arguments); // 这里的arguments 其实是foo 里的arguments
                  }, 100);
                }
                foo(2, 4, 6, 8) // args: [2, 4, 6, 8]

          },
          /*
            document.addEventListener('click',function(event){
              this.doSomething(event.type);
              return false;
            })
          */// 没有箭头是这样的写法吧！

          doSomething: function(type) {
            console.log('Handling ' + type  + ' for ' + this.id);
          }
        };
        /* 【解析：】
        *      在 init 方法中使用箭头函数，导致箭头函数里面的this 总是指向 handler 对象；
        *      不然，回调函数执行时，this.doSomething这一行报错，原因：this执行 document 对象
        * */
    // 总结：//
    /* 箭头函数没有自己的this，所以当然也就不能用【call()、apply()、bind()】这些方法去改变this的指向 */
    (function() {
      return [
        (() => this.x).bind({ x: 'inner' })() // 不会输入 inner
      ];
    }).call({ x: 'outer' });// ['outer'] 输出
    // 由于没有this 所以bind方法无效，内部的this指向外部的this

    /* 总结下的箭头函数 用ES5 写：
    (function(){
      return [
        (function(){
          return this.x
        }).bind({x: 'inner'})()
      ];
    }).call({x : 'outer'});

    */

    /** 自己探索吧 **/
    // 2. 不能使用new 关键字，就是不能把它当做构造函数
        /* 为啥不能：箭头函数没有自己的 this 导致内层的this就是外层代码块的 this */
    // 3. 没有arguments对象，要用请用rest参数
    // 4. 不可以使用 yield 命令【下面讲到】不能用作Generator函数
</script>
</body>
</html>